package dijkstry_seq;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.PriorityQueue;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

public class DijkstrySeq {

	private DocumentBuilderFactory docBuilderFactory;
	private DocumentBuilder docBuilder;
	private Document doc;
	private List<Vertex> vertexList = new ArrayList<Vertex>();
	
	public DijkstrySeq(String pathToXMLFile) {
		// TODO Auto-generated constructor stub
		fillVertexList(pathToXMLFile);
	}
	
	public void fillVertexList(String pathToXMLFile)
	{
		try {

            docBuilderFactory = DocumentBuilderFactory.newInstance();
            docBuilder = docBuilderFactory.newDocumentBuilder();
            doc = docBuilder.parse (new File(pathToXMLFile));
            doc.getDocumentElement ().normalize ();

            NodeList trList = doc.getElementsByTagName("tr");
            int trCount = trList.getLength();
            
            for(int s=0; s<trCount ; s++){

                Node node = trList.item(s);
                if(node.getNodeType() == Node.ELEMENT_NODE){

                    Element element = (Element)node;
                    String elementName = element.getAttribute("id");
                    vertexList.add(new Vertex(elementName));
                }
            }
            
            for(int s=0; s<trCount ; s++){

                Node node = trList.item(s);
                if(node.getNodeType() == Node.ELEMENT_NODE){

                    Element element = (Element)node;
                    NodeList tdList = element.getElementsByTagName("td");
                    
                    Vertex vertex = vertexList.get(s);
                    List<VertexWeight> connections = new ArrayList<>();
                    for(int i=0; i<tdList.getLength(); i++)
                    {
                    	Element tdElement = (Element)tdList.item(i);
                       	String tdValue = tdElement.getChildNodes().item(0).getNodeValue().trim();
                       	if(!tdValue.equals("0") && !tdValue.equals("-1"))
                       		connections.add(new VertexWeight(vertexList.get(i), Double.parseDouble(tdValue)));  	
                    }
                    for(int i=0; i<connections.size();i++)
                    {
                    	vertex.adjacencies.add(new Edge(connections.get(i).getVertex(), connections.get(i).getWeight()));
                    }
                }//end of if clause
            }//end of for loop with s var
        }catch (SAXParseException err) {
        System.out.println ("** Parsing error" + ", line " 
             + err.getLineNumber () + ", uri " + err.getSystemId ());
        System.out.println(" " + err.getMessage ());

        }catch (SAXException e) {
        Exception x = e.getException ();
        ((x == null) ? e : x).printStackTrace ();

        }catch (Throwable t) {
        t.printStackTrace ();
        }
	}
	
	public void computePaths(int source) throws IndexOutOfBoundsException
	{
		Vertex sourceVertex = vertexList.get(source);
	    sourceVertex.minDistance = 0.;
	    PriorityQueue<Vertex> vertexQueue = new PriorityQueue<Vertex>();
	    vertexQueue.add(sourceVertex);

	    while (!vertexQueue.isEmpty()) {
	        Vertex u = vertexQueue.poll();
	        // Visit each edge exiting u
	        for (Edge e : u.adjacencies)
	        {
	            Vertex v = e.target;
	            double weight = e.weight;
	            double distanceThroughU = u.minDistance + weight;
	            if (distanceThroughU < v.minDistance) {
	            	vertexQueue.remove(v);
	                v.minDistance = distanceThroughU ;
	                v.previous = u;
	                vertexQueue.add(v);
	            }
	        }
	    }
	}
	
	public List<Vertex> getShortestPathTo(int target) throws IndexOutOfBoundsException
	{
		Vertex targetVertex = vertexList.get(target);
	    List<Vertex> path = new ArrayList<Vertex>();
	    for (Vertex vertex = targetVertex; vertex != null; vertex = vertex.previous)
	        path.add(vertex);

	    Collections.reverse(path);
	    return path;
	}
	
}
